Mapped Tuple Type
Tが型変数の時、keyof TのTが配列やtupleだった場合の挙動が変わった 以前は
keyof unknown[] := "pop" | "push" | "concat" | "join" |..
の様にArrayのmethod名のunion型だった
v3.1以降では、
keyof unknown[] = number
の様に、numberのみが対象になる
Tが配列の時のkeyof Tはやや特殊な扱いになる、ということを頭に入れておけば良いmrsekut.icon
今の時代に、「v3.0以前と異なる」と説明されても全く有用ではない
(比較する機会はないので)
だから、「Tが配列以外の時と比較して特殊」と理解すればいい
とはいえ、直感に沿うようにするための変更なので、さほど深く考える必要はない
上記のPR内のコード例(一部改変)
準備
code:ts
type Box<T> = { value: T };
code:ts
type T1 = Boxified<string[]>;
// Box<string>[]
type T4 = Boxified<[number, ...string[]]>;
// [Box<number>, ...Box<string>[]]
type T6 = Boxified<(string | undefined)[]>;
// Box<string | undefined>[]
これ↓ は少し特殊だが、ほぼ同じ
code:ts
type T2 = Boxified<readonly string[]>;
// readonly Box<string>[]
Box<readonly string[]>の可能性も無きにしもあらずだが、これは配列ではない
「配列から配列へ変換される」というルールに則ったものなので理解しやすいmrsekut.icon
code:ts
type T5 = Boxified<string[] | undefined>;
// Box<string>[] | undefined
ditributeされたあとに、mapが行われている
Tが型引数なのかどうかで結果は変わる
code:ts
type n2b = n2t<n1>;
/**
* type n2 = {
* 0: 4;
* 1: 4;
* 2: 4;
* length: 4;
* toString: 4;
* ... 32 more ...;
* at: 4;
* }
*/
keyof Tが、
Tが型引数で、
Tが配列/tuple
のときだけ、lengthとかを無視してnumberになるよ
という話ねmrsekut.icon
genericsで無い時は、v3.0以前と同様に、keyof 配列は
keyof unknown[] := "pop" | "push" | "concat" | "join" |..
のように解釈されるので、上の例の様にぐちゃぐちゃの型になる
あくまでもnumberになっていることに注意
だから、以下のようなコードが通ってしまう
code:ts
const t1: keyof n1 = 1; // ok.
const t6: keyof n1 = 6; // ok!?
[F<E> for E in T]のような新たなsyntaxを入れて同様のことをしようというやつ
実際は、こういった新たなsyntaxは入れずに同様のことを実現している
関連する話